r"""
 main.py

 Tutt Library Systems Task Planner is a lightweight project management
 GAE application. The application
 uses Google Charts for visualization including the Ganett Charts based upon
 the following blog post:
 http://www.designinginteractive.com/code/how-to-build-a-gantt-chart-with-the-google-charts-api/

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 Copyright Jeremy Nelson, Colorado College
 """
__author__ = "Jeremy Nelson"
__version__ = "0.1.1"

import os,datetime,logging
import sys,urllib2
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from django.utils import simplejson as json
from mako.template import Template
from mako.lookup import TemplateLookup

from models import Person,Project,Role,System,Task

tuttsys_templates = TemplateLookup(
    directories=[os.path.join(os.path.dirname(__file__),
                              'templates')])


def create_user_url(handler):
    user = users.get_current_user()
    if user:
        return users.create_logout_url(handler.request.uri)
    else:
        return users.create_login_url(handler.request.uri)

class MainHandler(webapp.RequestHandler):
    """
    `MainHandler` main view for project management tasks and
    projects.
    """
    def get(self):
        user = users.get_current_user()
        query = db.GqlQuery('SELECT * FROM Project ORDER BY end_date')
        systems = System.all().order("name")        
        main_template = tuttsys_templates.get_template('default.html')
        self.response.out.write(main_template.render(listing=query.fetch(1000),
                                                     lib_systems=systems,
                                                     user=user,
                                                     user_url=create_user_url(self)))

class GanettChartHandler(webapp.RequestHandler):
    """
    `GanettChartHandler` view generates a simple Ganett-like chart
    of a rolling three-month snapshot of the projects
    """
    def get(self):
        ganett_template = tuttsys_templates.get_template('ganett.html')
        if self.request.GET.has_key('start'):
            start_date = self.request.GET['start']
        else:
            today = datetime.datetime.today()
            start_date = datetime.datetime(year=today.year,month=today.month,day=1)
        end_date = datetime.datetime(year=start_date.year,month=start_date.month+3,day=30)
        total_days = end_date - start_date
        self.x_axis = []
        for i in range(0,total_days.days):
            if not i%15:
                self.x_axis.append(start_date + datetime.timedelta(days=+i))
        query = db.GqlQuery('SELECT * FROM Project ORDER BY start_date')
        projects = query.fetch(1000)
        all_projects = []
        for project in projects:
            offset = self.__get_offset__(project.start_date)
            length = len(self.x_axis) - offset
            all_projects.append({'project':project,
                                 'length':length,
                                 'offset':offset})
        self.response.out.write(ganett_template.render(all_projects=all_projects,
                                                       title='Ganett Chart of Tutt Library Systems',
                                                       user = users.get_current_user(),
                                                       user_url=create_user_url(self),
                                                       x_axis=self.x_axis))

  
    def __get_offset__(self,start_date):
        """
        Helper method calculates offset grid class for project
   
        Parameters:
        `start_date`: start_date, required.
        """
        offset = 1
        for i,date in enumerate(self.x_axis):
            if i == len(self.x_axis) -1:
                pass
            else:
                next_date = self.x_axis[i+1]
                logging.error("START DATE=%s, DATE=%s NEXT=%s" % \
                              (start_date,date,next_date))
                if start_date >= date and not start_date < next_date:
                    offset += 1
        return offset

class ProjectHandler(webapp.RequestHandler):

    def get(self):
        project_id = self.request.GET['id']
        project = db.get(db.Key(project_id))
        project_template = tuttsys_templates.get_template('project.html')
        all_projects = []
        project_query = Project.all()
        for row in project_query:
            if row.key() != project.key():
                all_projects.append(row)
        all_tasks = []
        project_tasks = project.get_tasks()
        task_query = Task.all()
        for row in task_query:
            if project_tasks.count(row) < 1:
                all_tasks.append(row)
        self.response.out.write(project_template.render(project=project,
                                                        title='%s Project Details' % project.name,
                                                        all_projects=all_projects,
                                                        all_tasks=all_tasks,
                                                        user=users.get_current_user(),
                                                        user_url=create_user_url(self)))

class ProjectMethods(object):

    def route(self,request):
        key = request.get('id')
        project = db.get(db.Key(key))
        function = request.get('func')
        if function == 'add':
            property = request.get('name')
            value = request.get('value')
            if hasattr(project,property):
                if property.endswith('_date'):
                    value = datetime.datetime.strptime(value,'%m/%d/%Y')
                setattr(project,property,value)
                project.put()
                return True
        elif function == 'add_depend':
            target_key = db.Key(request.get('target'))
            if project.dependencies.count(target_key) < 1:
                project.dependencies.append(target_key)
                project.put()
                return True
        elif function == 'filter':
            return None
        elif function == 'rm_depend':
            target_key = db.Key(request.get('target'))
            if project.dependencies.count(target_key) > 0:
                project.dependencies.remove(target_key)
                project.put()
                return True
        elif function == 'rm_task':
            task_key = db.Key(request.get('target'))
            logging.error(type(task_key))
            logging.error("%s Count is %s" % (task_key,project.tasks.count(task_key)))
            logging.error(project.tasks)
            if project.tasks.count(task_key) > 0:
                project.tasks.remove(task_key)
                project.put()
                return True
        elif function == 'set_depend':
            target = db.get(db.Key(request.get('target')))
            if target.dependencies.count(project.key()) < 1:
                target.dependencies.append(project.key())
                target.put()
                return 'Added project as dependency'
            return 'Project not set as a dependency'
        elif function == 'update':
            property = request.get('name')
            value = request.get('value')
            if hasattr(project,property):
                if property.endswith('_date'):
                    value = datetime.datetime.strptime(value,'%m/%d/%Y')
                setattr(project,property,value)
                project.put()
                return True


 
class RPCHandler(webapp.RequestHandler):
    def __init__(self):
        webapp.RequestHandler.__init__(self)
        self.projects = ProjectMethods()
        self.tasks = TaskMethods()
        self.systems = SystemMethods()

    def get(self):
        self.error(403)
        return
    
    def post(self):
        user = users.get_current_user()
        entity_type = self.request.get('type')
        if not user and entity_type != 'system':
            self.error(403)
            return
        if entity_type == 'project':
            self.response.out.write(self.projects.route(self.request))
        elif entity_type == 'task':
            self.response.out.write(self.tasks.route(self.request))
        elif entity_type == 'system':
            self.response.out.write(self.systems.route(self.request))
        else:
            self.error(404)
            return

class SystemMethods(object):

    def check_url(self,raw_url):
        try:
            web_connection = urllib2.urlopen(raw_url)
            if web_connection.code  > 400:
                return {'status':'FAILURE','msg':'Code %s' % web_connection.code} 
            else:
                return {'status':'OK','msg':'Code %s' % web_connection.code}
        except:
            return {'status':'FAILURE','msg':'%s ' % sys.exc_info()[0]}


    def route(self,request):
        system_key = request.get('key')
        system = db.get(db.Key(system_key))
        func = request.get('func');
        if func == 'check':
            if system.url is not None:
                result = self.check_url(system.url)
                result['key'] = str(system.key())
                return json.dumps(result)
            else:
                return None
        elif func == 'info':
            output = {'name':system.name,
                      'key':str(system.key()),
                      'url':system.url,
                      'repo':system.src_repository_url}
            return json.dumps(output)
        elif func == 'save':
            return self.save_system(system,request)
        else:
            return None

    def save_system(self,system,request):
        if request.POST.has_key('name'):
            system.name = request.POST['name']
        if request.POST.has_key('url'):
            system.url = request.POST['url']
        if request.POST.has_key('repo'):
            system.src_repository_url = request.POST['repo']
        system.put()
        return 'Saved %s' % system.name




class TaskHandler(webapp.RequestHandler):

    def get(self):
        task_id = self.request.GET['id']
        task = db.get(db.Key(task_id))
        title ='%s Task Details' % task.description
        task_template = tuttsys_templates.get_template('task.html')
        self.response.out.write(task_template.render(task=task,
                                                     title=title,
                                                     user=users.get_current_user(),
                                                     user_url=create_user_url(self)))

class TaskMethods(object):

    def route(self,request):
        func = request.POST['func']
        task_key = request.POST['id'] 
        task = db.get(db.Key(task_key))
        if func == 'update':
            property = request.get('name')
            value = request.get('value')
            logging.error("UPDATE task, name=%s value=%s" % (property,value))
            if hasattr(task,property):
                if property.endswith('_date'):
                    value = datetime.datetime.strptime(value,'%m/%d/%Y')
                if value == 'True' or value == 'False':
                    value = bool(value)
                setattr(task,property,value)
                task.put()
                return True

    def save_task(self):
        pass



class VisualizationsHandler(webapp.RequestHandler):

    def get(self):
        self.response.out.write('IN DEVELOPMENT <a href="/ganett">Ganett Chart</a>')

def main():
    application = webapp.WSGIApplication([('/', MainHandler),
                                          ('/ganett',GanettChartHandler),
                                          ('/project',ProjectHandler),
                                          ('/rpc',RPCHandler),
                                          ('/task',TaskHandler),
                                          ('/visualizations',VisualizationsHandler)],
                                         debug=True)
    util.run_wsgi_app(application)

if __name__ == '__main__':
    main()
